using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using 凌依.工具库;
using 凌依.Xml;

public class 游戏数据管理器 : 单例_基础管理器<游戏数据管理器>
{
    private Xml文档工具 道具Xml;

    private Xml文档工具 贴图Xml;

    private Xml文档工具 种族信息Xml;

    private Xml文档工具 色彩信息Xml;

    private Dictionary<string, 物品数据> 道具字典 = new Dictionary<string, 物品数据>();//禁止更改,只可复制

    private Dictionary<string, 生物贴图> 贴图字典 = new Dictionary<string, 生物贴图>();

    private Dictionary<string, 种族信息> 种族字典 = new Dictionary<string, 种族信息>();

    private Dictionary<string, 色彩信息> 色彩信息字典 = new Dictionary<string, 色彩信息>();

    public void 读取配置文件(UnityAction 解析完成后)
    {
        string 道具Path = "数据/XML数据/道具/物品";
        道具Xml = new Xml文档工具(资源管理器.获取实例.加载<TextAsset>(道具Path).text);

        string 贴图path = "数据/XML数据/道具/贴图";
        贴图Xml = new Xml文档工具(资源管理器.获取实例.加载<TextAsset>(贴图path).text);

        string 种族信息path = "数据/XML数据/道具/信息";
        种族信息Xml = new Xml文档工具(资源管理器.获取实例.加载<TextAsset>(种族信息path).text);

        string 色彩信息path = "数据/XML数据/色彩信息/色彩渐变信息";
        色彩信息Xml = new Xml文档工具(资源管理器.获取实例.加载<TextAsset>(色彩信息path).text);

        帧更新控制器.获取实例.开启携程(解析配置文件(解析完成后));
        Debug.Log("读取完成");
    }

    #region 获取方法
    public 种族信息 获取种族信息(string 名称)
    {
        if (!种族字典.ContainsKey(名称))
            return null;
        return 种族字典[名称];
    }

    public T 获取色彩信息<T>(string name) where T : 色彩信息
    {
        if (!色彩信息字典.ContainsKey(name))
            return null;
        return 色彩信息字典[name] as T;
    }


    public T 获取生物贴图<T>(string 装备名) where T : 生物贴图
    {
        if (!贴图字典.ContainsKey(装备名))
            return null;
        物品数据 返回 = 贴图字典[装备名];
        T 新 = 返回 as T;
        return 新.克隆<T>();
    }
    /// <summary>
    /// 不可更改返回的类的值,否则全局都会更改
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public 地图物品 获取地图模板(string name)
    {
        if (道具字典.ContainsKey(name)){
            地图物品 返回 = 道具字典[name] as 地图物品;
            return 返回;
        }
        return null;
    }

    public 植物 获取植物模板(string name)
    {
        if (道具字典.ContainsKey(name))
        {
            植物 返回 = 道具字典[name] as 植物;
            return 返回;
        }
        return null;
    }

    public T 获取道具<T>(string 道具名) where T : 物品数据
    {
        if (!道具字典.ContainsKey(道具名))
            return null;
        物品数据 返回 = 道具字典[道具名];
        T 新 = 返回 as T;
        return 新.克隆<T>();
    }

    public T 获取道具_模板<T>(string 道具名) where T : 物品数据
    {
        if (!道具字典.ContainsKey(道具名))
            return null;
        物品数据 返回 = 道具字典[道具名];
        T 新 = 返回 as T;
        return 新;
    }

    public 地图物品 获取地图物品(string name)
    {
        return 获取道具<地图物品>(name);
    }
    public 道具物品 获取道具物品(string name)
    {
        return 获取道具<道具物品>(name);
    }
    #endregion

    IEnumerator 解析配置文件(UnityAction 解析完成后)
    {

        #region 色彩信息
        //有问题 TODO
        List<Xml节点> 节点s = 色彩信息Xml.根节点.查找节点_All("色彩");
        foreach (var 色彩 in 节点s)
        {
            string 类型 = 色彩.获取节点属性("类型");
            string 名称 = 色彩.获取节点属性("名称");
            switch (类型)
            {
                case "渐变":
                    色彩信息_渐变 jb = new 色彩信息_渐变();
                    jb.名称 = 名称;
                    jb.类型 = 类型;
                    jb.色彩 = 色彩.获取节点属性("起始色").ToColor();
                    jb.结束色 = 色彩.获取节点属性("结束色").ToColor();
                    色彩信息字典.Add(名称, jb);
                    break;
                case "单色":
                    色彩信息 jb1 = new 色彩信息();
                    jb1.名称 = 名称;
                    jb1.类型 = 类型;
                    jb1.色彩 = 色彩.获取节点属性("色彩").ToColor();
                    色彩信息字典.Add(名称, jb1);
                    break;
                case "集合":
                    色彩信息_集合 jb2 = new 色彩信息_集合();
                    jb2.名称 = 名称;
                    jb2.类型 = 类型;
                    List<Xml节点> xmls = 色彩.查找节点_All("列表");
                    foreach (var item in xmls)
                        jb2.预制色彩.Add(item.获取节点属性("色彩").ToColor());
                    色彩信息字典.Add(名称, jb2);
                    break;
                default:
                    break;
            }
        }

        #endregion

        #region 道具
        Xml节点 根节点 = 道具Xml.根节点.查找节点("物品");
        int 步骤 = 0;
        foreach (var 物品 in 根节点.查找节点_All("物品"))
        {
            步骤++;
            if (步骤 >= 100)
                yield return 0;


            string 名称 = 物品.获取节点属性("名称");
            string 类型 = 物品.获取节点属性("类型");
            Xml节点 属性 = 物品.查找节点("属性");
            //Debug.Log(名称);
            switch (类型)
            {
                #region 地图物品
                case "地图物品":
                    地图物品 a = new 地图物品();
                    a.名称 = 名称;
                    a.类型 = 类型;
                    a.描述 = 物品.查找节点("描述").节点值.Replace('*',',');
                    a.瓦片 = 游戏资源管理器.获取实例.获取瓦片(物品.查找节点("瓦片").节点值);
                    
                    a.叠加补色 = 属性.获取节点属性("叠加色").ToColor();
                    a.耐久 = int.Parse(属性.获取节点属性("耐久"));
                    a.材质 = 属性.获取节点属性("材质");

                    Xml节点 掉落物品 = 物品.查找节点("掉落物品");
                    if (掉落物品.子节点数量 >= 1)
                    {
                        List<Xml节点> xmls = 掉落物品.查找节点_All("列表");
                        //掉落道具类型 应该为数组
                        foreach (var item in xmls)
                        {
                            掉落数据 n = new 掉落数据(
                                item.获取节点属性("道具"), 
                                item.获取节点属性("最小数量").ToInt(), 
                                item.获取节点属性("最大数量").ToInt());
                            a.掉落信息.Add(n);
                        }
                    }
                    else
                    {
                        掉落数据 n = new 掉落数据(
                                掉落物品.获取节点属性("道具"),
                                掉落物品.获取节点属性("最小数量").ToInt(),
                                掉落物品.获取节点属性("最大数量").ToInt());
                        a.掉落信息.Add(n);
                    }

                    a.图层 = (图层)属性.获取节点属性("图层").ToInt();
                    道具字典.Add(名称, a);
                    break;
                #endregion
                #region 道具
                case "道具":
                    道具物品 b = new 道具物品();
                    b.名称 = 名称;
                    b.类型 = 类型;
                    b.描述 = 物品.查找节点("描述").节点值.Replace('*', ',');
                    b.贴图 = 游戏资源管理器.获取实例.获取贴图(物品.查找节点("贴图").节点值);
                    b.材质 = 属性.获取节点属性("材质");
                    b.叠加补色 = 属性.获取节点属性("叠加色").ToColor();
                    b.叠加上限 = 属性.获取节点属性("叠加上限").ToInt();
                    b.价值 = 属性.获取节点属性("价值").ToInt();
                    道具字典.Add(名称, b);
                    break;
                #endregion
                #region 植物
                case "植物":
                    植物 c = new 植物();
                    c.名称 = 名称;
                    c.类型 = 类型;
                    c.描述 = 物品.查找节点("描述").节点值.Replace('*', ',');
                    c.叠加补色 = 属性.获取节点属性("叠加色").ToColor();
                    c.生长周期 = 属性.获取节点属性("生长周期").ToInt();
                    c.生长进度 = c.生长周期;
                    c.耐久 = 属性.获取节点属性("耐久").ToInt();

                    Xml节点 掉落物品1 = 物品.查找节点("掉落物品");
                    if (掉落物品1.子节点数量 >= 1)
                    {
                        List<Xml节点> xmls = 掉落物品1.查找节点_All("列表");
                        //掉落道具类型 应该为数组
                        foreach (var item in xmls)
                        {
                            掉落数据 n = new 掉落数据(
                                item.获取节点属性("道具"),
                                item.获取节点属性("最小数量").ToInt(),
                                item.获取节点属性("最大数量").ToInt());
                            c.掉落信息.Add(n);
                        }
                    }
                    else
                    {
                        掉落数据 n = new 掉落数据(
                                掉落物品1.获取节点属性("道具"),
                                掉落物品1.获取节点属性("最小数量").ToInt(),
                                掉落物品1.获取节点属性("最大数量").ToInt());
                        c.掉落信息.Add(n);
                    }

                    Xml节点 贴图节点 = 物品.查找节点("贴图");
                    if (贴图节点.子节点数量 >= 1)
                    {
                        List<Xml节点> xmls = 贴图节点.查找节点_All("列表");
                        foreach (var item in xmls)
                            c.贴图.Add(游戏资源管理器.获取实例.获取贴图(item.获取节点属性("贴图")));
                    }
                    else
                        c.贴图.Add(游戏资源管理器.获取实例.获取贴图(贴图节点.获取节点属性("贴图")));
                    道具字典.Add(名称, c);
                    break;
                #endregion
                #region 器官信息
                case "器官":
                    器官信息 ret = new 器官信息();

                    ret.名称 = 名称;

                    ret.类型 = 类型;

                    ret.基因优越度 = 属性.获取节点属性("基因优越度").ToInt();

                    ret.品质 = (品质)属性.获取节点属性("品质").ToInt();

                    ret.器官类型 = 属性.获取节点属性("器官类型");

                    ret.有机体 = 属性.获取节点属性("有机体")=="1";

                    ret.耐久 = 属性.获取节点属性("耐久").ToInt();

                    ret.价值 = 属性.获取节点属性("价值").ToInt();

                    ret.描述 = 物品.查找节点("描述").节点值;

                    ret.叠加补色 = 获取色彩信息<色彩信息>(ret.品质.ToString()).色彩;

                    ret.增益属性 = new List<增益信息>();

                    Xml节点 增益节点 = 物品.查找节点("增益属性");
                    if(增益节点 != null)
                    {
                        List<Xml节点> 列表节点 = 增益节点.查找节点_All("列表");
                        if (列表节点.Count != 0)
                            foreach (var item in 列表节点)
                                ret.增益属性.Add(new 增益信息(item.获取节点属性("增益名"), item.获取节点属性("增益值").ToFloat()));
                        else
                        {
                            string name = 增益节点.获取节点属性("增益名");
                            if (name !=null && name!="")
                                ret.增益属性.Add(new 增益信息(增益节点.获取节点属性("增益名"), 增益节点.获取节点属性("增益值").ToFloat()));
                        }
                    }

                    道具字典.Add(名称, ret);
                    break;
                #endregion
                default:
                    Debug.LogError("解析道具发现未知类型:" + 类型);
                    控制台.获取实例.添加异常("解析道具发现未知类型:" + 类型);
                    break;

            }


        }
        #endregion

        #region 贴图
        Xml节点 贴图根节点 = 贴图Xml.根节点.查找节点("贴图");
        foreach (var 贴图 in 贴图根节点.查找节点_All("贴图"))
        {
            步骤++;
            if (步骤 >= 100)
                yield return 0;

            string 名称 = 贴图.获取节点属性("名称");
            string 类型 = 贴图.获取节点属性("类型");
            //Debug.Log(名称);

            Xml节点 属性 = 贴图.查找节点("属性");
            Xml节点 描述 = 贴图.查找节点("描述");
            Xml节点 贴图路径 = 贴图.查找节点("贴图");

            装备贴图 获取贴图(string 贴图名,string 贴图类型)
            {
                装备贴图 a = new 装备贴图();
                a.正面贴图 = 游戏资源管理器.获取实例.获取贴图(贴图名 + "_"+贴图类型+ "_south");
                a.侧面贴图 = 游戏资源管理器.获取实例.获取贴图(贴图名 + "_"+贴图类型+ "_east");
                a.背面贴图 = 游戏资源管理器.获取实例.获取贴图(贴图名 + "_"+贴图类型+ "_north");
                if (a.正面贴图 == null)
                    return null;
                return a;
            }

            switch (类型)
            {
                case "人形生物贴图":
                    人形生物贴图 ret1 = new 人形生物贴图();
                    ret1.名称 = 名称;
                    ret1.叠加补色 = 属性.获取节点属性("叠加色").ToColor();
                    ret1.性别 = 属性.获取节点属性("性别");
                    ret1.偏移值 = 属性.获取节点属性("偏移值").ToVector2();
                    ret1.描述 = 描述.节点值;
                    ret1.类型 = 类型;
                    ret1.贴图类型 = 属性.获取节点属性("贴图类型");
                    ret1.贴图 = new 装备贴图();
                    ret1.贴图.正面贴图 = 游戏资源管理器.获取实例.获取贴图(贴图路径.节点值 + "_south");
                    ret1.贴图.侧面贴图 = 游戏资源管理器.获取实例.获取贴图(贴图路径.节点值 + "_east");
                    ret1.贴图.背面贴图 = 游戏资源管理器.获取实例.获取贴图(贴图路径.节点值 + "_north");
                    贴图字典.Add(名称, ret1);
                    break;

                case "角色装备"://!!! 无任何属性加成,仅作为服装
                    角色装备 ret2 = new 角色装备();
                    ret2.名称 = 名称;
                    ret2.类型 = 类型;
                    ret2.叠加补色 = 属性.获取节点属性("叠加色").ToColor();
                    ret2.描述 = 描述.节点值;
                    ret2.品质 = (品质)属性.获取节点属性("品质").ToInt();
                    ret2.科技水平 = 属性.获取节点属性("科技水平");
                    ret2.装备层级 = (装备层级)属性.获取节点属性("装备层级").ToInt();

                    ret2.贴图_女性 = 获取贴图(贴图路径.节点值, "Female");
                    ret2.贴图_强壮 = 获取贴图(贴图路径.节点值, "Hulk");
                    ret2.贴图_男性 = 获取贴图(贴图路径.节点值, "Male");
                    ret2.贴图_瘦 = 获取贴图(贴图路径.节点值, "Thin");
                    ret2.贴图_胖 = 获取贴图(贴图路径.节点值, "Fat");

                    Xml节点 增益属性 = 贴图.查找节点("增益属性");
                    if (增益属性!=null && 增益属性.子节点数量 >= 1)
                    {
                        foreach (var item in 增益属性)
                        {
                            Xml节点 增益 = (Xml节点)item;
                            ret2.增益信息.Add(new 增益信息(增益.获取节点属性("增益名"), 增益.获取节点属性("增益值").ToFloat()));
                        }
                    }

                    道具字典.Add(名称, ret2);
                    break;
                default:
                    break;
            }
        }
        #endregion

        #region 数据集合
        Xml节点 种族信息根节点 = 种族信息Xml.根节点.查找节点("集合");
        foreach (var 种族信息 in 种族信息根节点.查找节点_All("集合"))
        {
            种族信息 信息 = new 种族信息();

            string name = 种族信息.获取节点属性("名称");
            信息.种族名称 = name;

            Xml节点 属性节点 = 种族信息.查找节点("属性");

            信息.基因优越度 = 属性节点.获取节点属性("优越度").ToInt();

            string 身体贴图名 = 种族信息.查找节点("身体贴图").获取节点属性("贴图名");

            信息.肉体 = 获取道具<角色装备>(身体贴图名).克隆<角色装备>();

            string 色彩名 = 属性节点.获取节点属性("叠加色名");

            string 发型色 = 属性节点.获取节点属性("发型色");

            if (!色彩信息字典.ContainsKey(色彩名))
                Debug.LogError(色彩名 + "-->不存在该色彩信息,来自加载物品种族信息");
            else
                信息.皮肤色 = 色彩信息字典[色彩名] as 色彩信息_渐变;

            if(发型色 != "")
            {
                if (!色彩信息字典.ContainsKey(发型色))
                    Debug.LogError(发型色 + "-->不存在该色彩信息,来自加载物品种族信息");
                else
                    信息.发型色 = 色彩信息字典[发型色] as 色彩信息_渐变;
            }
            

            信息.发型 = new List<人形生物贴图>();

            List<Xml节点> 发型节点 = 种族信息.查找节点("发型贴图").查找节点_All("列表");
            foreach (var item in 发型节点)
                信息.发型.Add(获取生物贴图<人形生物贴图>(item.获取节点属性("贴图名")));

            信息.面部 = new List<人形生物贴图>();
            List<Xml节点> 头像节点 = 种族信息.查找节点("头像贴图").查找节点_All("列表");
            foreach (var item in 头像节点)
                信息.面部.Add(获取生物贴图<人形生物贴图>(item.获取节点属性("贴图名")));


            //添加优越度信息
            string 优越度str = 种族信息.查找节点("器官优越度").节点值;
            Dictionary<string, int> 优越度 = new Dictionary<string, int>();

            string[] vs = 优越度str.Split('|');
            for (int i = 0; i < vs.Length; i++)
            {
                string dq = vs[i];
                string[] vs1 = dq.Split(':');
                if (!优越度.ContainsKey(vs1[0]))
                    优越度.Add(vs1[0], vs1[1].ToInt());
            }

            Xml节点 角色器官 = 种族信息.查找节点("角色器官");
            foreach (var item in 角色器官.查找节点_All("列表"))
            {
                string 器官名 = item.获取节点属性("器官名");
                器官信息 器官 = 获取道具_模板<器官信息>(器官名);
                信息.添加器官(器官, 优越度[器官.器官类型]);
            }

            Xml节点 增益信息 = 种族信息.查找节点("增益属性");
            if (增益信息 != null)
            {
                List<Xml节点> 增益节点 = 增益信息.查找节点_All("列表");
                if(增益节点==null || 增益节点.Count == 0)
                    信息.种族特殊效果.Add(new 增益信息(增益信息.获取节点属性("增益名"), 增益信息.获取节点属性("增益值").ToFloat()));
                else
                {
                    foreach (var item in 增益节点)
                    {
                        信息.种族特殊效果.Add(new 增益信息(item.获取节点属性("增益名"), item.获取节点属性("增益值").ToFloat()));
                    }
                }
            }
            种族字典.Add(信息.种族名称, 信息);
        }
        #endregion

        解析完成后();
    }
}
